/**
 * SFTP文件传输管理器
 * 使用node-ssh库实现跨平台文件传输
 * @author lihengtt <lihengsir@gmail.com>
 * @github https://github.com/lihengtt
 */
import { NodeSSH } from 'node-ssh';
import * as vscode from 'vscode';
import * as path from 'path';
import { ServerInfo } from './types';
import { RemoteFile } from './remoteExplorer';
import { LogManager } from './logManager';

export class SftpManager {
    private ssh: NodeSSH;
    private outputChannel: vscode.OutputChannel;
    private isConnected: boolean = false;
    private logger: LogManager;
    
    constructor() {
        this.ssh = new NodeSSH();
        this.outputChannel = vscode.window.createOutputChannel('SFTP Manager');
        this.logger = LogManager.getInstance();
    }

    /**
     * 检查是否已连接
     * @returns boolean - 连接状态
     * @author lihengtt <lihengsir@gmail.com>
     */
    isSSHConnected(): boolean {
        return this.isConnected && this.ssh.isConnected();
    }

    /**
     * 断开SSH连接
     * @author lihengtt <lihengsir@gmail.com>
     */
    async disconnect(): Promise<void> {
        try {
            if (this.isConnected) {
                this.ssh.dispose();
                this.isConnected = false;
                this.outputChannel.appendLine('SSH连接已断开');
            }
        } catch (error) {
            this.outputChannel.appendLine(`断开连接时发生错误: ${error}`);
        }
    }
    
    /**
     * 清理所有资源
     * 在插件停用时调用，确保SSH连接被正确关闭
     * @author lihengtt <lihengsir@gmail.com>
     */
    async cleanup(): Promise<void> {
        try {
            await this.disconnect();
            this.outputChannel.appendLine('SFTP管理器资源清理完成');
        } catch (error) {
            this.outputChannel.appendLine(`清理SFTP资源时发生错误: ${error}`);
        }
    }
    
    /**
     * 连接到远程服务器
     * @param serverInfo - 服务器连接信息
     * @returns Promise<boolean> - 连接是否成功
     * @author lihengtt <lihengsir@gmail.com>
     */
    async connect(serverInfo: ServerInfo): Promise<boolean> {
        try {
            this.outputChannel.appendLine(`尝试连接到 ${serverInfo.username}@${serverInfo.host}:${serverInfo.port}`);
            
            const connectionConfig: any = {
                host: serverInfo.host,
                port: serverInfo.port,
                username: serverInfo.username,
                readyTimeout: 30000,
                keepaliveInterval: 60000,
                keepaliveCountMax: 3,
                // 添加更多SSH选项以提高兼容性
                algorithms: {
                    kex: [
                        'diffie-hellman-group-exchange-sha256',
                        'diffie-hellman-group14-sha256',
                        'diffie-hellman-group16-sha512',
                        'diffie-hellman-group18-sha512',
                        'ecdh-sha2-nistp256',
                        'ecdh-sha2-nistp384',
                        'ecdh-sha2-nistp521'
                    ],
                    cipher: [
                        'aes128-gcm',
                        'aes128-gcm@openssh.com',
                        'aes256-gcm',
                        'aes256-gcm@openssh.com',
                        'aes128-ctr',
                        'aes192-ctr',
                        'aes256-ctr'
                    ],
                    hmac: [
                        'hmac-sha2-256-etm@openssh.com',
                        'hmac-sha2-512-etm@openssh.com',
                        'hmac-sha2-256',
                        'hmac-sha2-512',
                        'hmac-sha1'
                    ]
                },
                // 禁用严格的主机密钥检查
                hostVerifier: () => true
            };

            // 优先使用私钥认证
            if (serverInfo.privateKeyPath && serverInfo.privateKeyPath.trim() !== '') {
                this.outputChannel.appendLine('使用私钥认证');
                try {
                    const fs = require('fs');
                    if (fs.existsSync(serverInfo.privateKeyPath)) {
                        connectionConfig.privateKey = fs.readFileSync(serverInfo.privateKeyPath, 'utf8');
                        this.outputChannel.appendLine('私钥文件读取成功');
                    } else {
                        this.outputChannel.appendLine('私钥文件不存在，尝试密码认证');
                        connectionConfig.password = serverInfo.password;
                    }
                } catch (keyError) {
                    this.outputChannel.appendLine(`读取私钥失败: ${keyError}，尝试密码认证`);
                    connectionConfig.password = serverInfo.password;
                }
            } else if (serverInfo.password && serverInfo.password.trim() !== '') {
                this.outputChannel.appendLine('使用密码认证');
                connectionConfig.password = serverInfo.password;
            } else {
                throw new Error('请提供密码或私钥进行认证');
            }

            await this.ssh.connect(connectionConfig);
             this.isConnected = true;
             this.outputChannel.appendLine('SSH连接成功');
             return true;
        } catch (error) {
             this.isConnected = false;
             const errorMessage = `SSH连接失败: ${error}`;
             this.outputChannel.appendLine(errorMessage);
             vscode.window.showErrorMessage(errorMessage);
             return false;
         }
    }
    
    /**
     * 上传文件
     * @param localPath - 本地文件路径
     * @param remotePath - 远程文件路径
     * @returns Promise<boolean> - 上传是否成功
     * @author lihengtt <lihengsir@gmail.com>
     */
    async uploadFile(localPath: string, remotePath: string): Promise<boolean> {
        try {
            if (!this.isSSHConnected()) {
                throw new Error('SSH连接未建立，请先连接到服务器');
            }
            
            // 规范化本地文件路径
            const normalizedLocalPath = path.resolve(localPath);
            
            // 检查本地文件是否存在
            const fs = require('fs');
            if (!fs.existsSync(normalizedLocalPath)) {
                throw new Error(`本地文件不存在: ${normalizedLocalPath}`);
            }
            
            // 检查是否为文件（不是目录）
            const stats = fs.statSync(normalizedLocalPath);
            if (!stats.isFile()) {
                throw new Error(`路径不是文件: ${normalizedLocalPath}`);
            }
            
            // 规范化远程路径
            const normalizedRemotePath = remotePath.replace(/\\/g, '/').replace(/\/+/g, '/');
            
            this.logger.info(`上传文件: ${normalizedLocalPath} -> ${normalizedRemotePath}`, 'SftpManager');
            await this.ssh.putFile(normalizedLocalPath, normalizedRemotePath);
            this.logger.info('文件上传成功', 'SftpManager');
            return true;
        } catch (error) {
            const errorMessage = `上传失败: ${error}`;
            this.logger.error(errorMessage, 'SftpManager');
            vscode.window.showErrorMessage(errorMessage);
            return false;
        }
    }
    
    /**
     * 下载文件
     * @param remotePath - 远程文件路径
     * @param localPath - 本地文件路径
     * @returns Promise<boolean> - 下载是否成功
     * @author lihengtt <lihengsir@gmail.com>
     */
    async downloadFile(remotePath: string, localPath: string): Promise<boolean> {
        try {
            if (!this.isSSHConnected()) {
                throw new Error('SSH连接未建立，请先连接到服务器');
            }
            
            // 规范化路径
            const normalizedRemotePath = remotePath.replace(/\\/g, '/').replace(/\/+/g, '/');
            const normalizedLocalPath = path.resolve(localPath);
            
            // 确保本地目录存在
            const fs = require('fs');
            const localDir = path.dirname(normalizedLocalPath);
        if (!fs.existsSync(localDir)) {
            fs.mkdirSync(localDir, { recursive: true });
            this.logger.info(`创建本地目录: ${localDir}`, 'SftpManager');
            }
            
            this.logger.info(`下载文件: ${normalizedRemotePath} -> ${normalizedLocalPath}`, 'SftpManager');
            await this.ssh.getFile(normalizedLocalPath, normalizedRemotePath);
            this.logger.info('文件下载成功', 'SftpManager');
            return true;
        } catch (error) {
            const errorMessage = `下载失败: ${error}`;
            this.logger.error(errorMessage, 'SftpManager');
            vscode.window.showErrorMessage(errorMessage);
            return false;
        }
    }

    /**
     * 列出远程目录文件
     * @param remotePath - 远程目录路径
     * @returns Promise<RemoteFile[]> - 远程文件列表
     * @author lihengtt <lihengsir@gmail.com>
     */
    async listFiles(remotePath: string): Promise<RemoteFile[]> {
        try {
            if (!this.isSSHConnected()) {
                throw new Error('SSH连接未建立，请先连接到服务器');
            }
            
            // 规范化远程路径
            const normalizedRemotePath = remotePath.replace(/\\/g, '/').replace(/\/+/g, '/');
            
            this.logger.info(`列出远程目录: ${normalizedRemotePath}`, 'SftpManager');
            const files = await this.ssh.execCommand(`ls -la "${normalizedRemotePath}"`);
            
            if (files.code !== 0) {
                const errorMsg = files.stderr || '执行ls命令失败';
                this.logger.error(`ls命令执行失败 (退出码: ${files.code}): ${errorMsg}`, 'SftpManager');
                throw new Error(errorMsg);
            }
            
            const result = this.parseListOutput(files.stdout, normalizedRemotePath);
            this.logger.info(`找到 ${result.length} 个文件/目录`, 'SftpManager');
            return result;
        } catch (error) {
            const errorMessage = `列出文件失败: ${error}`;
            this.logger.error(errorMessage, 'SftpManager');
            vscode.window.showErrorMessage(errorMessage);
            return [];
        }
    }

    /**
     * 创建远程目录
     * @param remotePath - 远程目录路径
     * @returns Promise<boolean> - 是否成功
     * @author lihengtt <lihengsir@gmail.com>
     */
    async createDirectory(remotePath: string): Promise<boolean> {
        try {
            if (!this.isSSHConnected()) {
                throw new Error('SSH连接未建立，请先连接到服务器');
            }
            
            this.logger.info(`创建远程目录: ${remotePath}`, 'SftpManager');
        const result = await this.ssh.execCommand(`mkdir -p "${remotePath}"`);
        if (result.code === 0) {
            this.logger.info('目录创建成功', 'SftpManager');
            return true;
        } else {
                throw new Error(result.stderr || '创建目录命令执行失败');
            }
        } catch (error) {
            const errorMessage = `创建目录失败: ${error}`;
            this.logger.error(errorMessage, 'SftpManager');
            vscode.window.showErrorMessage(errorMessage);
            return false;
        }
    }

    /**
     * 删除远程文件或目录
     * @param remotePath - 远程文件路径
     * @param isDirectory - 是否为目录
     * @returns Promise<boolean> - 是否成功
     * @author lihengtt <lihengsir@gmail.com>
     */
    async deleteFile(remotePath: string, isDirectory: boolean = false): Promise<boolean> {
        try {
            if (!this.isSSHConnected()) {
                throw new Error('SSH连接未建立，请先连接到服务器');
            }
            
            const command = isDirectory ? `rm -rf "${remotePath}"` : `rm "${remotePath}"`;
            this.logger.info(`删除远程${isDirectory ? '目录' : '文件'}: ${remotePath}`, 'SftpManager');
        const result = await this.ssh.execCommand(command);
        if (result.code === 0) {
            this.logger.info(`${isDirectory ? '目录' : '文件'}删除成功`, 'SftpManager');
            return true;
        } else {
                throw new Error(result.stderr || '删除命令执行失败');
            }
        } catch (error) {
            const errorMessage = `删除失败: ${error}`;
            this.logger.error(errorMessage, 'SftpManager');
            vscode.window.showErrorMessage(errorMessage);
            return false;
        }
    }

    /**
     * 解析ls命令输出
     * @param output - ls命令输出
     * @param basePath - 基础路径
     * @returns RemoteFile[] - 解析后的文件列表
     * @author lihengtt <lihengsir@gmail.com>
     */
    private parseListOutput(output: string, basePath: string): RemoteFile[] {
        const files: RemoteFile[] = [];
        const lines = output.split('\n').filter(line => line.trim());

        for (const line of lines) {
            // 跳过总计行和当前目录、父目录
            if (line.startsWith('total') || line.includes(' .') || line.includes(' ..')) {
                continue;
            }

            const parts = line.trim().split(/\s+/);
            if (parts.length < 9) {
                continue;
            }

            const permissions = parts[0];
            const isDirectory = permissions.startsWith('d');
            const size = parseInt(parts[4]) || 0;
            const fileName = parts.slice(8).join(' ');
            // 修复路径拼接逻辑，避免重复拼接remotePath
            const filePath = basePath.endsWith('/') ? 
                `${basePath}${fileName}`.replace(/\/+/g, '/') : 
                `${basePath}/${fileName}`.replace(/\/+/g, '/');

            // 解析修改时间
            const month = parts[5];
            const day = parts[6];
            const timeOrYear = parts[7];
            let modifiedTime: Date | undefined;
            
            try {
                const currentYear = new Date().getFullYear();
                const dateStr = timeOrYear.includes(':') ? 
                    `${month} ${day} ${currentYear} ${timeOrYear}` :
                    `${month} ${day} ${timeOrYear}`;
                modifiedTime = new Date(dateStr);
            } catch {
                // 忽略日期解析错误
            }

            files.push({
                name: fileName,
                path: filePath,
                isDirectory,
                size: isDirectory ? undefined : size,
                modifiedTime,
                permissions
            });
        }

        return files.sort((a, b) => {
            // 目录排在前面
            if (a.isDirectory && !b.isDirectory) return -1;
            if (!a.isDirectory && b.isDirectory) return 1;
            // 按名称排序
            return a.name.localeCompare(b.name);
        });
    }

    /**
     * 显示输出通道
     * @author lihengtt <lihengsir@gmail.com>
     */
    showOutput(): void {
        this.outputChannel.show();
    }

    /**
     * 清空输出通道
     * @author lihengtt <lihengsir@gmail.com>
     */
    clearOutput(): void {
        this.outputChannel.clear();
    }
}